#pragma once

#include <iostream>
#include <memory>
#include "socket.hpp"

using namespace socket_net;
class SelectServer
{
    // 需要创建一个第三方数组来管理这个fd
    const static int N = sizeof(fd_set) * 8;
    const static int defaultfd = -1; // 默认fd为-1
public:
    SelectServer(uint16_t port) : _port(port), _ListenSock(make_unique<TcpSocket>())
    {
        InetAddr addr("0", _port);
        _ListenSock->BuildListenSocket(addr);
        memset(_fd_arry, -1, sizeof(_fd_arry));
        _fd_arry[0] = _ListenSock->sockfd();
    }
    ~SelectServer()
    {
    }
    void AcceptClient()
    {
        //只关心读，而读有listensock和normalsock
        InetAddr clientaddr;
        int sockfd=_ListenSock->Acceptaddr(&clientaddr);
        if(sockfd<0)
            return ;
        Log(DEBUG, "Get new Link, sockfd: %d, client info %s:%d\n", sockfd, clientaddr.ip().c_str(), clientaddr.port());
        // read/recv(sockfd); send(sockfd)?? 不能. 必须将新的fd，托管给select。如何托管呢？？？
        // 只要将新的fd添加到辅助数组中即可。
        int pos=1;
        for(;pos<N;pos++)
        {
            if(_fd_arry[pos]==defaultfd)
                break;
        }
        if(pos==N)
        {
            ::close(sockfd);
            Log(WARNING,"server is full...");
            return ;
        }
        else
        {
            _fd_arry[pos]=sockfd;
            Log(DEBUG,"%d add to select arry!",sockfd);
        }
    Log(DEBUG, "curr fd_array[] fd list : %s", RfdsToString().c_str());
    }
    
    void ServerIO(int pos)
    {
        char buffer[1024];
        ssize_t n=::recv(_fd_arry[pos],buffer,sizeof(buffer)-1,0);
        if(n>0)
        {
            buffer[n]=0;
            cout<<"client say# "<<buffer<<endl;
            string echostring="[server echo#] ";
            echostring+=buffer;
            ::send(_fd_arry[pos],echostring.c_str(),echostring.size(),0);
        }
        else if(n==0)
        {
            Log(DEBUG,"%d is closed",_fd_arry[pos]);
            ::close(_fd_arry[pos]);
            _fd_arry[pos]=defaultfd;
           Log(DEBUG, "curr fd_array[] fd list : %s", RfdsToString().c_str());
        }
        else
        {
            Log(DEBUG,"%d recv is error",_fd_arry[pos]);
            ::close(_fd_arry[pos]);
            _fd_arry[pos]=defaultfd;
           Log(DEBUG, "curr fd_array[] fd list : %s", RfdsToString().c_str());
        }
    }
    void HanderEvents(fd_set&rfd)
    {
        for(int i=0;i<N;i++)
        {
            if(_fd_arry[i]==defaultfd)  continue;
            if(FD_ISSET(_fd_arry[i],&rfd))
            {
                if(_fd_arry[i]==_ListenSock->sockfd())
                {
                    AcceptClient();
                }
                else{
                    //普通sockfd读事件
                    cout<<"96"<<endl;
                    ServerIO(i);
                }
            }
        }
    }
    std::string RfdsToString()
    {
        std::string fdstr;
        for (int i = 0; i < N; i++)
        {
            if (_fd_arry[i] == defaultfd)
                continue;
            fdstr += std::to_string(_fd_arry[i]);
            fdstr += " ";
        }
        return fdstr;
    }
    void loop()
    {
        while (true)
        {
            // listensocket 等待新连接到来，等价于对方给我发送数据！我们作为读事件同一处理
            // 新连接到来 等价于 读事件就绪！
            // 首先要将listensock添加到select中！
            fd_set rfd;
            FD_ZERO(&rfd);
            int maxfd = defaultfd;
            for (int i = 0; i < N; i++)
            {
                if (_fd_arry[i] == defaultfd)
                    continue;
                FD_SET(_fd_arry[i], &rfd); // 将合法的fd添加到rfd中
                if (maxfd < _fd_arry[i])
                {
                    maxfd = _fd_arry[i];//更新最大的fd
                }
            }

            struct timeval timeout = {1, 0};
            int n = select(maxfd + 1, &rfd, nullptr, nullptr, nullptr/*&timeout*/);

            switch (n)
            {
            case 0:
                Log(DEBUG, "timeout.....%d:%d", timeout.tv_sec, timeout.tv_usec);
                break;
            case -1:
                Log(DEBUG, "select error...");
                break;
            default:
                Log(DEBUG, "Event things happen!n: %d",n);
                HanderEvents(rfd);
                break;
            }
        }
    }

private:
    uint16_t _port;
    unique_ptr<Socket> _ListenSock;
    int _fd_arry[N];
};